package com.like.banzipao.server.plugins

import com.like.banzipao.server.db.DatabaseHelper
import com.like.banzipao.server.getCurrentUser
import com.like.banzipao.server.getFormItemMap
import com.like.banzipao.server.model.Coupons
import com.like.banzipao.server.model.Msg
import com.like.banzipao.server.model.MsgType
import com.like.banzipao.server.model.Room
import com.like.banzipao.server.model.User
import com.like.banzipao.server.model.getCoupons
import com.like.banzipao.server.model.users
import com.like.banzipao.server.respondError
import com.like.banzipao.server.respondSuccess
import com.like.banzipao.server.util.objectMapper
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.auth.authenticate
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.route
import io.ktor.server.routing.routing
import org.ktorm.dsl.eq
import org.ktorm.entity.add
import org.ktorm.entity.find
import org.ktorm.entity.update
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicInteger

private val roomId = AtomicInteger(-1)
val rooms = CopyOnWriteArrayList<Room>()

fun getRoom(userId: Int): Room? {
    return rooms.find { it.manager.contains(userId) }
}

fun getRoom(user: User): Room? {
    return rooms.find { it.manager.contains(user) }
}

fun Application.configureRouting() {
    routing {
        get("/") {
            call.respondText("Hello World!")
        }
        post("/login-register") {
            val formItemMap = call.getFormItemMap()
            val name = formItemMap.getOrDefault("name", "")
            val password = formItemMap.getOrDefault("password", "")
            if (name.isEmpty()) {
                call.respondError("用户名不能为空！")
                return@post
            }
            if (password.isEmpty()) {
                call.respondError("密码不能为空！")
                return@post
            }
            var user = DatabaseHelper.database.users.find { it.name eq name }
            if (user == null) {// 注册
                user = User {
                    this.name = name
                    this.password = password
                    this.token = simpleJwt.sign(name)
                }
                if (DatabaseHelper.database.users.add(user) > 0) {
                    call.respondSuccess(user)
                } else {
                    call.respondError("登录失败！")
                }
            } else {// 登录
                if (user.password == password) {
                    call.respondSuccess(user)
                } else {
                    call.respondError("用户名或者密码错误！")
                }
            }
        }
        authenticate {// 需要添加 Authentication 的 Bearer Token 来验证
            // 我们可以使用 route(path) { } 块将具有相同前缀的路由分组。
            route("/room") {
                post("/create") {
                    val user = call.getCurrentUser()
                    if (user == null) {
                        call.respondError("请先登录")
                        return@post
                    }
                    if (getRoom(user) != null) {
                        call.respondError("你已经在房间中了，无法再次创建房间！")
                        return@post
                    }

                    val formItemMap = call.getFormItemMap()
                    val drawNumber = formItemMap.getOrDefault("drawNumber", "-1").toInt()
                    if (drawNumber < 0) {
                        call.respondError("换牌数量设置无效！")
                        return@post
                    }

                    val room = Room(roomId.incrementAndGet())
                    room.drawNumber = drawNumber
                    room.manager.addPlayer(user)
                    rooms.add(room)

                    broadcast(Msg(MsgType.ROOM, room))
                    call.respondSuccess(Unit)
                }
                post("/in") {
                    val user = call.getCurrentUser()
                    if (user == null) {
                        call.respondError("请先登录")
                        return@post
                    }
                    val formItemMap = call.getFormItemMap()
                    val roomId = formItemMap.getOrDefault("roomId", "-1").toInt()
                    if (roomId < 0) {
                        call.respondError("房号无效！")
                        return@post
                    }
                    val room = rooms.find { it.id == roomId }
                    if (room == null) {
                        call.respondError("房间不存在！")
                        return@post
                    }
                    if (room.manager.isFull()) {
                        call.respondError("房间已满！")
                        return@post
                    }
                    if (room.manager.contains(user)) {
                        call.respondError("你已经在房间 ${room.id} 中！")
                        return@post
                    }
                    room.manager.addPlayer(user)

                    broadcast(Msg(MsgType.ROOM, room))
                    call.respondSuccess(Unit)
                }
                post("/out") {
                    val user = call.getCurrentUser()
                    if (user == null) {
                        call.respondError("请先登录")
                        return@post
                    }
                    val room = getRoom(user)
                    if (room == null) {
                        call.respondError("请先加入房间")
                        return@post
                    }
                    room.manager.removePlayer(user)
                    if (room.manager.isEmpty()) {
                        rooms.remove(room)
                    }
                    broadcast(Msg(MsgType.ROOM, room))
                    call.respondSuccess(Unit)
                }
            }
            route("/game") {
                post("/ready") {
                    val user = call.getCurrentUser()
                    if (user == null) {
                        call.respondError("请先登录")
                        return@post
                    }
                    val room = getRoom(user)
                    if (room == null) {
                        call.respondError("请先加入房间")
                        return@post
                    }
                    try {
                        room.manager.ready(user)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    } catch (e: Exception) {
                        call.respondError(e.message)
                    }
                }
                post("/again") {
                    val user = call.getCurrentUser()
                    if (user == null) {
                        call.respondError("请先登录")
                        return@post
                    }
                    val room = getRoom(user)
                    if (room == null) {
                        call.respondError("请先加入房间")
                        return@post
                    }
                    try {
                        room.manager.again(user)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    } catch (e: Exception) {
                        call.respondError(e.message)
                    }
                }
                route("/bao") {
                    post("/") {
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        room.manager.bao(user)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                    post("/fan") {
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        room.manager.fanBao(user)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                    post("/pass") {
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        room.manager.baoPass(user)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                    post("/fan/pass") {
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        room.manager.fanBaoPass(user)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                }
                route("/draw") {// 换牌
                    post("/played") {
                        val formItemMap = call.getFormItemMap()
                        val ids = formItemMap.getOrDefault("ids", "").split(",").map { it.toInt() }
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        if (ids.size != room.drawNumber) {
                            call.respondError("交换牌数量必须为 ${room.drawNumber}！")
                            return@post
                        }
                        if (ids.contains(room.manager.getSpade7()?.id)) {
                            call.respondError("不能换牌黑桃7！")
                            return@post
                        }
                        room.manager.drawPlayed(user, ids)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                    post("/take") {
                        val formItemMap = call.getFormItemMap()
                        val ids = formItemMap.getOrDefault("ids", "").split(",").map { it.toInt() }
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        if (ids.size != room.drawNumber) {
                            call.respondError("获取牌数量必须为 ${room.drawNumber}！")
                            return@post
                        }
                        room.manager.drawTake(user, ids)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                }
                route("/friend") {
                    post("/all") {
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        call.respondSuccess(room.manager.getAllFindFriendPokers())
                    }
                    post("/find") {
                        val formItemMap = call.getFormItemMap()
                        val id = formItemMap.getOrDefault("id", "").toInt()
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        room.manager.findFriend(user, id)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                }
                route("/play") {
                    post("/played") {
                        val formItemMap = call.getFormItemMap()
                        val ids = formItemMap.getOrDefault("ids", "").split(",").map { it.toInt() }
                        if (ids.isEmpty()) {
                            call.respondError("出牌数量无效！")
                            return@post
                        }
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        if (!room.manager.playPlayed(user, ids)) {
                            call.respondError("无效出牌")
                            return@post
                        }
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                    post("/pass") {
                        val user = call.getCurrentUser()
                        if (user == null) {
                            call.respondError("请先登录")
                            return@post
                        }
                        val room = getRoom(user)
                        if (room == null) {
                            call.respondError("请先加入房间")
                            return@post
                        }
                        room.manager.playPass(user)
                        broadcast(Msg(MsgType.ROOM, room))
                        call.respondSuccess(Unit)
                    }
                }
            }
            post("/couponsList") {
                val user = call.getCurrentUser()
                if (user == null) {
                    call.respondError("请先登录")
                    return@post
                }
                call.respondSuccess(getCoupons())
            }
            post("/buyRoomCard") {
                val user = call.getCurrentUser()
                if (user == null) {
                    call.respondError("请先登录")
                    return@post
                }

                val formItemMap = call.getFormItemMap()
                val couponsJson = formItemMap.getOrDefault("coupons", "")
                val coupons = objectMapper.readValue(couponsJson, Coupons::class.java)
                if (coupons == null) {
                    call.respondError("购买失败，请联系客服！")
                    return@post
                }

                user.roomCard += coupons.number
                if (DatabaseHelper.database.users.update(user) > 0) {
                    // 如果是在房间中购买的房卡，则需要更新对应房间
                    getRoom(user)?.apply {
                        for (player in this.players) {
                            if (player?.user?.id == user.id) {
                                player.user.roomCard = user.roomCard
                                break
                            }
                        }
                        broadcast(Msg(MsgType.ROOM, this))
                    }
                    call.respondSuccess(user)
                } else {
                    user.roomCard -= coupons.number
                    call.respondError("购买失败，请联系客服！")
                }
            }
        }
    }
}
